/*
 * cxxomfort example: localfn
 * 
 * This program provides sample usage of the 
 * "local function" emulation feature.
 */

//#define CXXOMFORT_NOTICES 10
#include <cxxomfort/cxxomfort.hpp>
#include <cxxomfort/library/localfn.hpp> // localfn
#include <cxxomfort/random.hpp> // minstd_rand
#include <deque>
#include <iterator>
#include <numeric>
#include <ctime> // time
#include <iostream>

/*
 * The demonstration consists of:
 * 
 * * reading a number of random numbers from the system
 * * using localfn, modding and altering the numbers to fit within a given range
 * * using localfn, obtain the words expression of the numbers
 */

const unsigned NUMS=25;

typedef std::deque<unsigned int> SqT;

std::ostream& operator<< (std::ostream&, SqT const&);

int main () {
    using namespace std;
    cout<< boolalpha;
    minstd_rand rG (time(0));
    cout<< "Generating "<< NUMS<< "."<< endl;
    SqT lista;
    generate_n( back_inserter(lista), NUMS, ref(rG));
    cout<< "generados: "<< lista<< endl;
    SqT modifs( lista.size() );
    iota( begin(modifs), end(modifs), time(0)%60 );
    cout<< "modificadores: "<< modifs<< endl;

    size_t pares=0;
    size_t modclaves=0;

    CXXO_LOCALFN(X,int(int,int), size_t& pares, size_t& modclaves ) (int r, int q) {
        if (r % 2 == 0) ++pares;
        if (r % q == 0) ++modclaves;
        r%= q;
        return r;
    }
    X (size_t& pares, size_t& modclaves) : CXXO_LOCALFN_BIND(pares,modclaves);
    //CXXO_LOCALFN_INIT(X,alterar,(pares, modclaves) );
    CXXO_LOCALFN_NAME_DEF(X,alterar,(pares,modclaves));

    cout<< endl;
    transform( begin(lista), end(lista), begin(modifs), begin(lista), alterar);
    cout<< "lista1 = "<< lista<< endl;
    cout<< "pares="<< pares<< endl;
    cout<< endl;

    CXXO_LOCALFN(Y,int(int)) (int orig) {
        return 1 + orig;
    }
    CXXO_LOCALFN_NAME_DEF(Y,sumy);
    
    SqT lista2(lista.size());
    transform(begin(lista), end(lista), begin(lista2), sumy);
    cout<< "lista2 = "<< lista2<< endl;
}


std::ostream& operator<< (std::ostream& os, SqT const& S) {
    using namespace std;
    if (S.empty()) {
        os<< "[]";
    } else {
        os<< S.size()<< " : [ ";
        SqT::const_iterator cx= begin(S);
        os<< *cx++;
        for (; cx != end(S); ++cx) {
            os<< ", "<< *cx;
        }
        os<< " ]";
    }
    return os;
}
